#include "test04_Struct.h"


#include<iostream>

// 结构体
// 结构体可定义在类中，也可定义在类外，两者的作用域不同，区别主要在于可见性、命名空间和成员函数的访问方式上
// 类里的结构体 - 定义在.h文件中
//    使用时当成普通变量，在类内部可以直接使用结构体的名称，而不需要使用限定符
//    对于类内部的成员和函数是可见的，并且可以直接访问类的私有成员
//    如果结构体定义在类内部，那么在类内部定义的成员函数可以直接访问结构体的成员，无需使用限定符


// 类外的结构体 - 定义在.h文件的class外
//    定义在类外部的结构体的名称在全局命名空间中，因此它的名称与类的成员和函数有着不同的命名空间
//    对于类的成员和函数是不可见的，需要通过类对象或类的静态成员来访问
//    如果结构体定义在类外部，类的成员函数需要使用限定符（类名+作用域解析运算符）才能够访问结构体的成员
//    如果结构体定义在类外部，可以将结构体的声明和定义分别放在头文件和源文件中，实现分离编译。
//		这样，在多个源文件中包含同一个结构体的声明时，可以减少重复编译，提高编译效率

// .h和.cpp文件分别写的内容
// @1 - .h文件
//		写类的声明(包括类里面的成员和方法声明)，函数原型，#define常数宏等，一般不写具体的实现
//		一般加预编译语句，防止重复编译 #ifndef CIRCLE_H(名称一般为头文件_H)   #define CIRCLE_H   //你的代码写在这里   #endif
//		头文件中只处理常量，变量，函数，类的声明，所有实现都在源文件中。头文件不编译，每个cpp文件会被编译成.obj文件
//			然后所有obj文件链接起来形成可执行程序
// @2 - .cpp文件
//		写头文件中已经声明的函数的具体代码，在开头必须#include一下要实现的头文件，以及其他要用到的头文件
//		是
//@3 - package
//		定义 - 一个package是由同名的.h和.cpp文件组成，但可以少任意一个，若只有.h文件，则package是接口/模板(template)的定义
//			只有.cpp的package可以是一个程序的入口
//		参考 - https://www.cnblogs.com/fenghuan/p/4794514.html
//
//

void test04_Struct::clsMain()
{
	// 函数或结构中访问其成员，推荐使用(箭头，表示指向，指针) -> 

	structTe struTe = { 0,0 }; // 使用前要初始化，分配内存，赋值初始化
	structTe* struTe2 = new structTe; // new开辟堆内存
	struTe2->a = 8;
	struTe2->b = 8;
	// 传值和传地址
	this->structTeOfFunction(struTe);
	this->structTePointOfFun(&struTe);
	std::cout << "函数外获取到的结构体地址：" << &struTe << std::endl;
	// 当向两个不同的函数传递同一个结构体时，一个函数接受结构体地址作为参数，另一个函数接受结构体值作为参数，
	// 通过使用"&"访问到的值是相同的。
	// 这是因为传递结构体地址时，实际上是将结构体的内存地址传递给函数，而不是进行拷贝。
	// 因此，在函数中通过指针访问结构体的成员时，所访问到的是原始结构体的值

	// 传指针的另一种形式
	std::cout << "另一种形式" << std::endl;
	this->structTePointOfFun(struTe2);
	std::cout << "外部-地址：" << &struTe2 << std::endl;
	structTe stu0;
	stu0 = functionRequestStruct(); // 函数返回值为结构体
	std::cout << stu0.b;


	// 结构体指针的初始化
	structByExternalClass* sbec = new structByExternalClass; // 指向结构体的指针
	sbec->sa = 2;
	sbec->sb = 2;
	//this->useExternalClassStruct(sbec);


}


// 结构体做函数参数 --- 按值传递
void test04_Struct::structTeOfFunction(structTe x)
{
	std::cout << "structTeOfFunction 传递值" << "\n";
	// 函数内部定义一个结构体变量
	structTe stTe = { 1,2 }; // 使用前要初始化
	std::cout << stTe.a;
	std::cout << "访问参数中的结构体元素 x.a：" << x.a << std::endl;
	std::cout << "函数内获取到的结构体地址：" << &x << "\n";
}

// 结构体做函数返回值
// 哪个类::类里的结构体 哪个类::类中方法
test04_Struct::structTe test04_Struct::functionRequestStruct()
{
	test04_Struct::structTe se;
	se.a = 9;
	se.b = 9;
	return se;
}


// 结构体指针做函数参数 = 传地址
void test04_Struct::structTePointOfFun(const structTe* x)
{
	std::cout << "structTePointOfFun 传地址" << "\n";
	std::cout << x->b << "\n";
	std::cout << "Point函数内获取到的结构体地址：" << & x << "\n";
}


// 使用类外的结构体，类外结构体指针做函数参数
void test04_Struct::useExternalClassStruct(structByExternalClass* sbP)
{
	// 初始化结构体
	structByExternalClass sbc = { 1,1 };
	std::cout << "类外部的结构体：" << sbc.sb << "\n";
	std::cout << "结构体参数：" << sbP->sa << "\n";
}

// 自定义out返回多个值
//void test04_Struct::divide(int dividend, int divisor, out<int>& quotient_out, out<int>& remainder_out)
//{
//	quotient_out.emplace(dividend / divisor);
//	remainder_out.emplace(dividend % divisor);
//}
